package com.tanhua.server.service;

import com.fasterxml.jackson.databind.util.BeanUtil;
import com.tanhua.commons.template.AliyunOssTemplate;
import com.tanhua.domain.db.User;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.mongo.Comment;
import com.tanhua.domain.mongo.Publish;
import com.tanhua.domain.mongo.Visitor;
import com.tanhua.domain.vo.ErrorResult;
import com.tanhua.domain.vo.PageResult;
import com.tanhua.domain.vo.PublishVO;
import com.tanhua.domain.vo.VisitorVO;
import com.tanhua.dubbo.api.*;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.server.util.RelativeDateFormat;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class MovementsService {
    @Reference
    private UserApi userApi;
    @Reference
    private PublishApi publishApi;
    @Reference
    private UserInfoApi userInfoApi;

    @Reference
    private CommentApi commentApi;
    @Reference
    private VisitorApi visitorApi;
    @Autowired
    private AliyunOssTemplate ossTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private MovementMQService movementMQService;

    private PageResult findMovementListFromRedis(int page, int pagesize) {
        //1. 从redis里获取推荐的动态，是逗号分隔的pid 20,22,20,110003,17,110004,23,110004,26,110006
        String idStr = redisTemplate.opsForValue().get("QUANZI_PUBLISH_RECOMMEND_" + UserHolder.getUser().getId());
        if (idStr == null) {
            return null;
        }

        //2. 查询总数量
        String[] idArray = idStr.split(",");
        int count = idArray.length;

        //3. 计算总页数
        int pages = (int) Math.ceil(count * 1.0 / pagesize);

        //4. 查询数据列表
        //4.1  如果查询的页码，大于总页数，返回null
        if (page > pages) {
            return null;
        }
        //4.2  计算分页查询相关的起止索引值
        int start = (page - 1) * pagesize;
        int end = start + pagesize;
        if (end > count) {
            end = count;
        }
        //4.3  获取索引范围内的pid
        List<Long> pidList = new ArrayList<>();
        for (int i = start; i < end; i++) {
            pidList.add(Long.parseLong(idArray[i]));
        }

        //4.4 根据pid列表，找到对应的动态列表
        List<Publish> list = publishApi.findPublishListByPids(pidList);

        return new PageResult<>(count, pagesize, pages, page, list);
    }
//

    public ResponseEntity recommendMovementList(int page, int pagesize) {
        //1. 获取当前用户
        User user = UserHolder.getUser();

        //2. 分页查询推荐给当前用户的动态列表PageResult里是Publish对象
        //2.1 优先从redis中查询 大数据推荐的动态
        PageResult pageResult = findMovementListFromRedis(page, pagesize);
        //2.2 如果没有推荐，再从MongoDB里查询
        if (pageResult == null) {
            pageResult = publishApi.findRecommendList(user.getId(), page, pagesize);
        }
        //3. 转换成vo
        List<Publish> publishList = pageResult.getItems();
        List<PublishVO> voList = new ArrayList<>();

        for (Publish publish : publishList) {
            PublishVO vo = new PublishVO();

            //1. 把发布人的信息封装到vo里
            UserInfo userInfo = userInfoApi.findById(publish.getUserId());
            BeanUtils.copyProperties(userInfo, vo);
            vo.setUserId(userInfo.getId());
            if (userInfo.getTags() != null) {
                vo.setTags(userInfo.getTags().split(","));
            }


            //2. 把动态Publish本身封装到vo里
            BeanUtils.copyProperties(publish, vo);
            vo.setId(publish.getId().toHexString());
            vo.setDistance("50米");
            vo.setImageContent(publish.getMedias().toArray(new String[]{}));
            vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));
            Boolean hasLiked = redisTemplate.hasKey("publish_like_" + user.getId() + "_" + publish.getId().toHexString());
            vo.setHasLiked(hasLiked ? 1 : 0);
            vo.setHasLoved(0);

            voList.add(vo);
        }

        pageResult.setItems(voList);

        return ResponseEntity.ok(pageResult);
    }

    public ResponseEntity friendsMovementList(int page, int pagesize) {
        User user = UserHolder.getUser();
        PageResult pageResult = publishApi.findFriendMovementList(user.getId(), page, pagesize);
        List<Publish> publishList = pageResult.getItems();
        List<PublishVO> voList = new ArrayList<>();
        for (Publish publish : publishList) {
            PublishVO vo = new PublishVO();

            UserInfo userInfo = userInfoApi.findById(publish.getUserId());
            BeanUtils.copyProperties(userInfo, vo);
            vo.setUserId(userInfo.getId());
            if (userInfo.getTags() != null) {
                vo.setTags(userInfo.getTags().split(","));
            }
            BeanUtils.copyProperties(publish, vo);
            vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));
            vo.setImageContent(publish.getMedias().toArray(new String[]{}));
            vo.setId(publish.getId().toHexString());
            vo.setDistance("50米");
            Boolean hasLiked = redisTemplate.hasKey("publish_like_" + user.getId() + "_" + publish.getId().toHexString());
            vo.setHasLiked(hasLiked ? 1 : 0);
            Boolean hasLoved = redisTemplate.hasKey("publish_love_" + user.getId() + "_" + publish.getId().toHexString());
            vo.setHasLoved(hasLoved ? 1 : 0);
            voList.add(vo);
        }
        pageResult.setItems(voList);

        return ResponseEntity.ok(pageResult);
    }

    public ResponseEntity all(int page, int pagesize, Long userId) {
        if (userId == null) {

            userId = UserHolder.getUser().getId();
        }
        PageResult pageResult = publishApi.findAll(userId, page, pagesize);

        List<Publish> publishList = pageResult.getItems();
        List<PublishVO> voList = new ArrayList<>();
        for (Publish publish : publishList) {
            PublishVO vo = new PublishVO();
            vo.setId(publish.getId().toHexString());
            UserInfo userInfo = userInfoApi.findById(publish.getUserId());
            BeanUtils.copyProperties(userInfo, vo);
            if (userInfo.getTags() != null) {
                vo.setTags(userInfo.getTags().split(","));
            }
            BeanUtils.copyProperties(publish, vo);
            vo.setImageContent(publish.getMedias().toArray(new String[]{}));
            vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));
            vo.setDistance("50米");
            Boolean hasLiked = redisTemplate.hasKey("publish_like_" + userId + "_" + publish.getId().toHexString());
            vo.setHasLiked(hasLiked ? 1 : 0);
            Boolean hasLoved = redisTemplate.hasKey("publish_love_" + userId + "_" + publish.getId().toHexString());
            vo.setHasLoved(hasLoved ? 1 : 0);
            voList.add(vo);
        }
        pageResult.setItems(voList);
        return ResponseEntity.ok(pageResult);
    }

    /**
     * 发布动态
     * @param publish
     * @param imageContentArray
     * @return
     * @throws IOException
     */
    public ResponseEntity savePublish(Publish publish, MultipartFile[] imageContentArray) throws IOException {
        //1. 获取当前用户
        User user = UserHolder.getUser();
        String phone = user.getMobile();

        Boolean freezingTime = redisTemplate.hasKey("FreezingTime" + phone);
        //如果还在冻结时间内，并且冻结范围是1，才禁止登录
        //如果冻结时间结束，则当前用户冻结范围也取消
        if (!freezingTime) {
            redisTemplate.delete("FreezingRange" + phone);
        } else {
            //是冻结的情况下,也就是非空，或者是类型3的情况下，不可以发布动态
            String number = redisTemplate.opsForValue().get("FreezingRange" + phone);
            if (number != null && "3".equals(number)) {
                return ResponseEntity.status(500).body(ErrorResult.banPublished());
            }
        }
        //2. 上传图片
        List<String> medias = new ArrayList<>();
        if (imageContentArray != null && imageContentArray.length > 0) {
            for (MultipartFile file : imageContentArray) {
                String url = ossTemplate.upload(file.getOriginalFilename(), file.getInputStream());
                medias.add(url);
            }
        }
        publish.setMedias(medias);

        //3. 保存动态
        publish.setUserId(user.getId());
        publish.setState(0);
        String publishId = publishApi.save(publish);
        rocketMQTemplate.convertAndSend("tanhua-publish", publishId);
        movementMQService.sendSavePublishMsg(publishId);

        return ResponseEntity.ok(null);
    }

    public ResponseEntity like(String publishId) {
        Long userId = UserHolder.getUser().getId();
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setUserId(userId);
        comment.setCommentType(1);
        comment.setPubType(1);
        int count = (int) commentApi.save(comment);
        redisTemplate.opsForValue().set("publish_like_" + userId + "_" + publishId, "1");
        movementMQService.sendLikePublishMsg(publishId);
        return ResponseEntity.ok(count);
    }

    public ResponseEntity dislike(String publishId) {
        Long userId = UserHolder.getUser().getId();
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setUserId(userId);
        comment.setCommentType(1);
        comment.setPubType(1);
        int count = (int) commentApi.remove(comment);
        redisTemplate.delete("publish_like_" + userId + "_" + publishId);
        movementMQService.sendUnlikePublishMsg(publishId);
        return ResponseEntity.ok(count);
    }

    public ResponseEntity love(String publishId) {
        Long userId = UserHolder.getUser().getId();
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setUserId(userId);
        comment.setPubType(1);
        comment.setCommentType(3);
        int count = commentApi.save(comment);
        redisTemplate.opsForValue().set("publish_love_" + userId + "_" + publishId, "1");
        return ResponseEntity.ok(count);
    }

    public ResponseEntity unlove(String publishId) {
        Long userId = UserHolder.getUser().getId();
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));
        comment.setPubType(1);
        comment.setCommentType(3);
        int count = commentApi.remove(comment);
        redisTemplate.delete("publish_love_" + userId + "_" + publishId);
        return ResponseEntity.ok(count);
    }

    public ResponseEntity findOnePublish(String publishId) {
        //查询publishId对应的动态
        Publish publish = publishApi.findById(publishId);

        //把动态发布人信息封装到vo里
        PublishVO vo = new PublishVO();
        UserInfo userInfo = userInfoApi.findById(publish.getUserId());
        BeanUtils.copyProperties(userInfo, vo);
        if (userInfo.getTags() != null) {
            vo.setTags(userInfo.getTags().split(","));
        }

        //把动态信息封装到 vo里
        BeanUtils.copyProperties(publish, vo);
        vo.setId(publish.getId().toHexString());
        vo.setImageContent(publish.getMedias().toArray(new String[]{}));
        vo.setDistance("50米");
        vo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));
        Boolean hasLike = redisTemplate.hasKey("publish_like_" + UserHolder.getUser().getId() + "_" + publish.getId().toHexString());
        //当前用户是否喜欢,点赞了
        vo.setHasLiked(hasLike ? 1 : 0);
        vo.setHasLoved(0);
        return ResponseEntity.ok(vo);
    }

    public ResponseEntity findVisitorsList() {

        //查找当前用户
        User user = UserHolder.getUser();
        //判断上次查看的时间
        String time = redisTemplate.opsForValue().get("visitor_time_" + user.getId());
        List<Visitor> visitorList = null;
        if (time == null) {
            //没有将会返回前五个
            visitorList = visitorApi.findVisitorListByCount(user.getId(), 5);
        } else {
            //返回最近的几个
            visitorList = visitorApi.findVisitorListByStartDate(user.getId(), Long.valueOf(time));
        }
        redisTemplate.opsForValue().set("visitor_time_" + user.getId(), String.valueOf(System.currentTimeMillis()));
        List<VisitorVO> voList = new ArrayList<>();
        for (Visitor visitor : visitorList) {
            VisitorVO vo = new VisitorVO();
            UserInfo userinfo = userInfoApi.findById(visitor.getVisitorUserId());
            BeanUtils.copyProperties(userinfo, vo);
            voList.add(vo);
        }

        return ResponseEntity.ok(voList);
    }


}
